package com.elh.lock;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @author liulei
 **/
@Slf4j
@SuppressWarnings("unchecked")
public class RedisUnFairDistributeLock implements IUnFairDistributeLock {

    public static final String LOCK_PREFIX = "lock:";

    @Autowired
    private RedisTemplate redisTemplate;

    private static DefaultRedisScript<String> lockRedisScript;

    private static DefaultRedisScript<String> unLockRedisScript;

    static {
        lockRedisScript = new DefaultRedisScript();
        lockRedisScript.setLocation(new ClassPathResource("lock.lua"));
        lockRedisScript.setResultType(String.class);
        unLockRedisScript = new DefaultRedisScript();
        unLockRedisScript.setLocation(new ClassPathResource("unlock.lua"));
        unLockRedisScript.setResultType(String.class);
    }


    @Override
    public String lock(String key, long timeOut, TimeUnit timeUnit) {
        long millTimeOut = TimeUnit.MILLISECONDS.convert(timeOut, timeUnit);
        String uuid = IdUtil.fastSimpleUUID();
        while((millTimeOut) < System.currentTimeMillis()){
            String result = Convert.toStr(redisTemplate.execute(lockRedisScript, Collections.singletonList(LOCK_PREFIX + key), uuid, 60));
            if(StrUtil.equals(result,"1")){
                return uuid;
            }
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                log.warn("线程中断异常:{}",e);
            }
        }
        return uuid;
    }

    @Override
    public boolean unlock(String key,String value) {
        String result = Convert.toStr(redisTemplate.execute(unLockRedisScript, Collections.singletonList(LOCK_PREFIX + key), value));
        return StrUtil.equals(result,"0");
    }
}
